﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
using Infrastructure;
using SubsDownloader.Core;
using SubsDownloader.Core.AppSettings;
using SubsDownloader.Core.Entities;
using SubsDownloader.Core.EventArgs;
using Timer = System.Threading.Timer;

namespace SubsDownloader
{
    public partial class SubsDownloaderControl : UserControl
    {
        #region Data Members
        private readonly object _syncObject = new object();

        private DownloaderManager _subsDownloaderManager;
        private readonly List<TitleFileInfo> _titles = new List<TitleFileInfo>();
        private DateTime _lastTimeItemInserted;
        private readonly TimeSpan _loadingTime = new TimeSpan( 0, 0, 0, 2 );

        private Dictionary<TitleFileInfo, NoMatchSubtitleFoundEventArgs> _subtitleResultses;
        private Dictionary<TitleFileInfo, NoMatchTitleFoundEventArgs> _titleResultses;

        private AboutBox _aboutBox;

        private TreeNode _allNode;
        private TreeNode _moviesNode;
        private TreeNode _seriesNode;
        private Timer _refreshTimer;
        #endregion


        public SubsDownloaderControl ()
        {
            InitializeComponent();
            _refreshTimer = new Timer( RefreshItems, null, 1000, Timeout.Infinite );
        }

        private void RefreshItems ( object state )
        {
            try
            {
                var loading = ( DateTime.Now - _lastTimeItemInserted <= _loadingTime );
                if (!loading)
                {
                    InvokeIfRequired( () =>
                        {
                            _toolStripStatusLabelLoading.Text = string.Empty;
                            CheckTree();
                        } );
                }
            }
            catch (Exception)
            {
            }
            finally
            {
                _refreshTimer.Change( 1000, Timeout.Infinite );
            }
        }

        #region Object List View

        private void FastObjectListViewSelectedIndexChanged ( object sender, EventArgs e )
        {
            TitleFileInfo titleFileInfo = GetSelectedItem();
            if (titleFileInfo == null)
                return;

            _listBoxSelection.Items.Clear();
            //_listBoxLog.Items.Clear();
            _listBoxLog.DataSource = titleFileInfo.Logger;
            tabControl1.TabPages.Remove( _tabPageSelect );

            if (_titleResultses.ContainsKey( titleFileInfo ))
            {
                tabControl1.TabPages.Add( _tabPageSelect );
                _listBoxSelection.Items.AddRange( _titleResultses[titleFileInfo].MovieResults );
                tabControl1.SelectedTab = _tabPageSelect;
            }

            else if (_subtitleResultses.ContainsKey( titleFileInfo ))
            {
                tabControl1.TabPages.Add( _tabPageSelect );
                _listBoxSelection.Items.AddRange( _subtitleResultses[titleFileInfo].SubtitleResults );
                tabControl1.SelectedTab = _tabPageSelect;
            }
            _fastObjectListView.Focus();
        }

        private object OnImageGetter ( object x )
        {
            object retVal;
            switch (( (TitleFileInfo)x ).Status)
            {
                case eStatus.New:
                    retVal = imageList1.Images["new"];
                    break;
                case eStatus.Pause:
                    retVal = imageList1.Images["pause"];
                    break;
                case eStatus.Process:
                    //retVal = imageList1.Images["process"];
                    retVal = imageList1.Images["working"];
                    break;
                case eStatus.Sucess:
                    retVal = imageList1.Images["success"];
                    break;
                case eStatus.Fail:
                    retVal = imageList1.Images["fail"];
                    break;
                default:
                    retVal = null;
                    break;
            }
            return retVal;
        }

        private string OnAspectToStringConverter ( object x )
        {
            return String.Empty;
        }

        private object OnAspectGetter ( object x )
        {
            return ( (TitleFileInfo)x ).HasSubs;
        }

        private void FastObjectListViewDragEnter ( object sender, DragEventArgs e )
        {
            e.Effect = e.Data.GetDataPresent( DataFormats.FileDrop ) ? DragDropEffects.Copy : DragDropEffects.None;
        }

        private void FastObjectListViewDragDrop ( object sender, DragEventArgs e )
        {
            var datas = (string[])e.Data.GetData( DataFormats.FileDrop );
            InitManagerIfNeeded();
            foreach (var data in datas)
            {
                string data1 = data;
                ThreadPool.QueueUserWorkItem( s =>
                {
                    _lastTimeItemInserted = DateTime.Now;
                    if (Directory.Exists( data1 ))
                    {
                        var files = Directory.GetFiles( data1, "*.*", SearchOption.AllDirectories );
                        foreach (var file in files)
                        {
                            _subsDownloaderManager.DownloadSubtitles( file );
                        }
                    }
                    else if (File.Exists( data1 ))
                    {
                        _subsDownloaderManager.DownloadSubtitles( data1 );
                    }
                } );
            }
        }
        #endregion

        #region SubDownloader

        private void SubsDownloaderManagerFileRecived ( object arg1, TitleFileInfo titleFileInfo )
        {
            lock (_syncObject)
            {
                _titles.Add( titleFileInfo );
            }
            titleFileInfo.ItemChanged += new EventHandler( titleFileInfo_ItemChanged );

            _lastTimeItemInserted = DateTime.Now;
            InvokeIfRequired( () => _toolStripStatusLabelLoading.Text = titleFileInfo.FilePath );
        }

        void titleFileInfo_ItemChanged ( object sender, EventArgs e )
        {
            _fastObjectListView.RefreshObject( sender );
        }

        private void SubsDownloaderManagerNoSubtitleMatchFound ( object sender, NoMatchSubtitleFoundEventArgs e )
        {
            if (_subtitleResultses.ContainsKey( e.TitleFileInfo ))
            {
                _subtitleResultses.Remove( e.TitleFileInfo );
            }
            _subtitleResultses.Add( e.TitleFileInfo, e );
        }

        private void SubsDownloaderManagerNoTitleMatchFound ( object sender, NoMatchTitleFoundEventArgs e )
        {
            if (_titleResultses.ContainsKey( e.TitleFileInfo ))
            {
                _titleResultses.Remove( e.TitleFileInfo );
            }
            _titleResultses.Add( e.TitleFileInfo, e );
        }


        #endregion

        private void MyInitComponents ()
        {
            _subtitleResultses = new Dictionary<TitleFileInfo, NoMatchSubtitleFoundEventArgs>();
            _titleResultses = new Dictionary<TitleFileInfo, NoMatchTitleFoundEventArgs>();

            _olvColumnStatus.AspectGetter = OnAspectGetter;
            _olvColumnStatus.AspectToStringConverter = OnAspectToStringConverter;
            _olvColumnStatus.ImageGetter = OnImageGetter;

            var folderScanerSettings = SettingsManager.Instane.GetSettings<FolderScanerSettings>();
            _toolStripButtonStart.Enabled = folderScanerSettings.FolderToMonitor.Count > 0;
            _aboutBox = new AboutBox();

            if (ParentForm != null)
            {
                ParentForm.Text = string.Format( "{0} {1}", ParentForm.Text, Assembly.GetExecutingAssembly().GetName().Version );
            }


            _allNode = _treeViewTitlesView.Nodes.Add( "All" );
            _allNode.Tag = _titles;
            _moviesNode = _allNode.Nodes.Add( "Movies" );
            _moviesNode.Tag = new List<TitleFileInfo>();
            _seriesNode = _allNode.Nodes.Add( "Series" );
            _seriesNode.Tag = new List<TitleFileInfo>();

        }

        private void UserControl1_Load ( object sender, EventArgs e )
        {
            MyInitComponents();
            if (ParentForm != null)
            {
                ParentForm.Closing += ParentForm_Closing;
                ParentForm.Load += ParentForm_Load;
            }
            _timer.Start();
        }

        void ParentForm_Load ( object sender, EventArgs e )
        {
            splitContainer2.SplitterDistance = Properties.Settings.Default.SplitterDistance;
        }

        void ParentForm_Closing ( object sender, System.ComponentModel.CancelEventArgs e )
        {
            Properties.Settings.Default.SplitterDistance = splitContainer2.SplitterDistance;
        }

        private void InvokeIfRequired ( Action action )
        {
            if (InvokeRequired)
                Invoke( action );
            else
                action();
        }

        private TitleFileInfo GetSelectedItem ()
        {
            if (_fastObjectListView.SelectedObject == null) return null;

            var titleFileInfo = (TitleFileInfo)_fastObjectListView.SelectedObject;
            return titleFileInfo;
        }

        private void TimerTick ( object sender, EventArgs e )
        {
            //check if can run subs downloader manager
            if (_subsDownloaderManager != null && _subsDownloaderManager.Running)
            {
                _toolStripButtonStart.Enabled = false;
                _toolStripButtonStop.Enabled = true;
            }
            else
            {
                var folderScanerSettings = SettingsManager.Instane.GetSettings<FolderScanerSettings>();
                _toolStripButtonStart.Enabled = folderScanerSettings.FolderToMonitor.Count > 0;
                _toolStripButtonStop.Enabled = !_toolStripButtonStart.Enabled;
            }

            var seriesCount = _titles.ToArray().Where( t => t.IsSeries ).Count();
            _toolStripStatusLabelToalFiles.Text = string.Format( "{0} ([Movies: {1}] [Series: {2}])", _titles.Count, _titles.Count - seriesCount, seriesCount );
        }

        private void CheckTree ()
        {
            var seriesWithoutSubs = new Dictionary<string, bool>();
            foreach (var titleFileInfo in _titles)
            {
                if (titleFileInfo.IsSeries)
                {
                    var seasonNodeText = string.Format( "Season {0}", titleFileInfo.Season );
                    var episodeNodeText = string.Format( "Episode {0}", titleFileInfo.Episode );
                    var series = ( (List<TitleFileInfo>)_seriesNode.Tag );
                    if (!series.Contains( titleFileInfo ))
                    {
                        series.Add( titleFileInfo );
                    }                   
                    TreeNode seriesNode = GetNode( _seriesNode, titleFileInfo.TitleName, titleFileInfo );
                    TreeNode seasonNode = GetNode( seriesNode, seasonNodeText, titleFileInfo );
                    TreeNode episodeNode = GetNode( seasonNode, episodeNodeText, titleFileInfo );


                    if (!seriesWithoutSubs.ContainsKey( titleFileInfo.TitleName ))
                    {
                        seriesWithoutSubs.Add( titleFileInfo.TitleName, titleFileInfo.HasSubs );
                    }

                    if (!titleFileInfo.HasSubs)
                    {
                        seriesWithoutSubs[titleFileInfo.TitleName] = titleFileInfo.HasSubs;
                        episodeNode.ForeColor = Color.Red;
                    }
                    else
                    {
                        episodeNode.ForeColor = Color.Black;
                    }

                    if (!seriesWithoutSubs[titleFileInfo.TitleName])
                    {
                        seriesNode.ForeColor = Color.Red;
                        seasonNode.ForeColor = Color.Red;
                    }
                    else
                    {
                        seriesNode.ForeColor = Color.Black;
                        seasonNode.ForeColor = Color.Black;
                    }

                }
                else
                {
                    TreeNode movieNode = GetNode( _moviesNode, titleFileInfo.TitleName, titleFileInfo );
                    var movies = ( (List<TitleFileInfo>)_moviesNode.Tag );
                    if (!movies.Contains( titleFileInfo ))
                    {
                        movies.Add( titleFileInfo );
                    }                   
                    movieNode.ForeColor = titleFileInfo.HasSubs ? Color.Black : Color.Red;
                }

            }
        }

        private TreeNode GetNode ( TreeNode parentNode, string nodeName, TitleFileInfo titleFileInfo )
        {
            TreeNode seasonNode;
            if (!parentNode.Nodes.ContainsKey( nodeName ))
            {
                seasonNode = parentNode.Nodes.Add( nodeName, nodeName );
                seasonNode.Tag = new List<TitleFileInfo>();
                ( (List<TitleFileInfo>)seasonNode.Tag ).Add( titleFileInfo );
            }
            else
            {
                seasonNode = parentNode.Nodes[nodeName];
                var list = ( (List<TitleFileInfo>)seasonNode.Tag );
                if (!list.Contains( titleFileInfo ))
                {
                    list.Add( titleFileInfo );
                }
            }
            return seasonNode;
        }

        private void TextBoxFindTextChanged ( object sender, EventArgs e )
        {
            TitleFileInfo titleFileInfo = GetSelectedItem();
            if (titleFileInfo == null)
                return;

            if (string.IsNullOrEmpty( _textBoxFind.Text ))
            {
                _listBoxSelection.Items.Clear();
                if (_titleResultses.ContainsKey( titleFileInfo ))
                {
                    _listBoxSelection.Items.AddRange( _titleResultses[titleFileInfo].MovieResults );
                }

                else if (_subtitleResultses.ContainsKey( titleFileInfo ))
                {
                    _listBoxSelection.Items.AddRange( _subtitleResultses[titleFileInfo].SubtitleResults );
                }
            }
            else if (_titleResultses.ContainsKey( titleFileInfo ))
            {
                _listBoxSelection.Items.Clear();
                var matchTitleFoundEventArgs = _titleResultses[titleFileInfo];
                foreach (var movieResult in matchTitleFoundEventArgs.MovieResults)
                {
                    if (movieResult.Name.ToLower().Contains( _textBoxFind.Text.ToLower() ))
                    {
                        _listBoxSelection.Items.Add( movieResult );
                    }
                }
            }
            else if (_subtitleResultses.ContainsKey( titleFileInfo ))
            {
                _listBoxSelection.Items.Clear();
                var matchSubtitleFoundEventArgs = _subtitleResultses[titleFileInfo];
                foreach (var subtitleResult in matchSubtitleFoundEventArgs.SubtitleResults)
                {
                    if (subtitleResult.Name.ToLower().Contains( _textBoxFind.Text.ToLower() ))
                    {
                        _listBoxSelection.Items.Add( subtitleResult );
                    }
                }
            }
        }

        private void ListBoxSelectionDoubleClick ( object sender, EventArgs e )
        {
            if (_listBoxSelection.SelectedItem == null)
                return;

            if (_listBoxSelection.SelectedItem is TitleResult)
            {
                TitleFileInfo titleFileInfo = ( (TitleResult)_listBoxSelection.SelectedItem ).Title;
                var titleResult = (TitleResult)_listBoxSelection.SelectedItem;
                _subsDownloaderManager.DownloadSubtitles( titleFileInfo, titleResult );

                _titleResultses.Remove( titleFileInfo );
                tabControl1.TabPages.Remove( _tabPageSelect );
            }
            else if (_listBoxSelection.SelectedItem is SubtitleResult)
            {
                TitleFileInfo titleFileInfo = ( (SubtitleResult)_listBoxSelection.SelectedItem ).Title;
                var subtitleResult = (SubtitleResult)_listBoxSelection.SelectedItem;
                _subsDownloaderManager.DownloadSubtitles( titleFileInfo, subtitleResult );

                _subtitleResultses.Remove( titleFileInfo );
                tabControl1.TabPages.Remove( _tabPageSelect );
            }
        }

        private void ButtonCancelSelectClick ( object sender, EventArgs e )
        {
            var titleFileInfo = GetSelectedItem();
            if (titleFileInfo == null) return;
            if (_subtitleResultses.ContainsKey( titleFileInfo ))
            {
                _subtitleResultses.Remove( titleFileInfo );
                tabControl1.TabPages.Remove( _tabPageSelect );
            }
            else if (_titleResultses.ContainsKey( titleFileInfo ))
            {
                _titleResultses.Remove( titleFileInfo );
                tabControl1.TabPages.Remove( _tabPageSelect );
            }
            _subsDownloaderManager.CancelDownload( titleFileInfo );
        }

        private void TreeViewTitlesViewAfterSelect ( object sender, TreeViewEventArgs e )
        {
            //CheckTree();
            var titleFileInfos = (List<TitleFileInfo>)e.Node.Tag;
            lock (_syncObject)
            {
                _fastObjectListView.SetObjects( titleFileInfos );
                if(titleFileInfos.Count >0 )
                {
                    _fastObjectListView.SelectedIndex = 0;
                }
                else
                {
                    _fastObjectListView.SelectedIndex =-1;
                }
            }
        }

        #region Context Menu

        private void ReSearchToolStripMenuItemClick ( object sender, EventArgs e )
        {
            if (_fastObjectListView.SelectedObjects != null)
            {
                foreach (var titleInfo in _fastObjectListView.SelectedObjects.Cast<TitleFileInfo>())
                {
                    _subsDownloaderManager.DownloadSubtitles( titleInfo, true );
                }
            }
            else
            {
                TitleFileInfo titleFileInfo = GetSelectedItem();
                if (titleFileInfo == null)
                    return;

                _subsDownloaderManager.DownloadSubtitles( titleFileInfo );
            }
        }

        private void ContextMenuStripOpening ( object sender, System.ComponentModel.CancelEventArgs e )
        {
            var titleFileInfo = GetSelectedItem();
            if (_fastObjectListView.SelectedObjects == null)
            {
                e.Cancel = true;
            }
            else
            {
                if (_fastObjectListView.SelectedObjects.Count == 1)
                {
                    ignoreToolStripMenuItem.Visible = true;
                    thisSeriesToolStripMenuItem.Visible = titleFileInfo.IsSeries;
                    thisSeasonToolStripMenuItem.Visible = titleFileInfo.IsSeries;
                    thisEpisodeToolStripMenuItem.Visible = titleFileInfo.IsSeries;
                    thisMovieToolStripMenuItem.Visible = !titleFileInfo.IsSeries;
                }
                else
                {
                    ignoreToolStripMenuItem.Visible = false;
                }
            }
        }

        private void OpenContatiningFolderToolStripMenuItemClick ( object sender, EventArgs e )
        {
            var titleFileInfo = GetSelectedItem();
            if (titleFileInfo == null) return;
            Process.Start( titleFileInfo.FolderPath );
        }

        private void CopyNameToolStripMenuItemClick ( object sender, EventArgs e )
        {
            var titleFileInfo = GetSelectedItem();
            if (titleFileInfo == null) return;
            Clipboard.SetText( titleFileInfo.TitleName );
        }

        private void CopyFileNameToolStripMenuItemClick ( object sender, EventArgs e )
        {
            var titleFileInfo = GetSelectedItem();
            if (titleFileInfo == null) return;
            Clipboard.SetText( titleFileInfo.FileNameNoExt );
        }

        private void CopyFullPathToolStripMenuItemClick ( object sender, EventArgs e )
        {
            var titleFileInfo = GetSelectedItem();
            if (titleFileInfo == null) return;

            Clipboard.SetText( titleFileInfo.FilePath );
        }

        #endregion

        #region Menue Strip

        private void ThisMovieToolStripMenuItemClick ( object sender, EventArgs e )
        {
            var tilte = GetSelectedItem();
            var folderScanerSettings = SettingsManager.Instane.GetSettings<FolderScanerSettings>();
            folderScanerSettings.IgnoredMedia.Add( tilte.ToString() );
            SettingsManager.Instane.SaveSettings();
        }

        private void ThisSeriesToolStripMenuItemClick ( object sender, EventArgs e )
        {
            var tilte = GetSelectedItem();
            var folderScanerSettings = SettingsManager.Instane.GetSettings<FolderScanerSettings>();
            folderScanerSettings.IgnoredMedia.Add( tilte.TitleName );
            SettingsManager.Instane.SaveSettings();
        }

        private void ThisSeasonToolStripMenuItemClick ( object sender, EventArgs e )
        {
            var tilte = GetSelectedItem();
            var folderScanerSettings = SettingsManager.Instane.GetSettings<FolderScanerSettings>();
            folderScanerSettings.IgnoredMedia.Add( tilte.ToString( "S" ) );
            SettingsManager.Instane.SaveSettings();
        }

        private void ExitToolStripMenuItemClick ( object sender, EventArgs e )
        {
            Environment.Exit( 0 );
        }

        private void OptionsToolStripMenuItemClick ( object sender, EventArgs e )
        {
            var optionsDlg = new OptionsDlg();
            var dialogResults = optionsDlg.ShowDialog();
            if (dialogResults == DialogResult.OK)
            {
                _subsDownloaderManager = new DownloaderManager();
                _subsDownloaderManager.FileRecived += SubsDownloaderManagerFileRecived;
                _subsDownloaderManager.NoTitleMatchFound += SubsDownloaderManagerNoTitleMatchFound;
                _subsDownloaderManager.NoSubtitleMatchFound += SubsDownloaderManagerNoSubtitleMatchFound;
            }
        }

        private void OpenFileToolStripMenuItemClick ( object sender, EventArgs e )
        {
            if (_openFileDialog.ShowDialog() == DialogResult.OK)
            {
                foreach (var fileName in _openFileDialog.FileNames)
                {
                    InitManagerIfNeeded();
                    _subsDownloaderManager.DownloadSubtitles( fileName );
                }
            }
        }

        private void ToolStripButton2Click ( object sender, EventArgs e )
        {
            if (_folderBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                _lastTimeItemInserted = DateTime.Now;
                ThreadPool.QueueUserWorkItem( s =>
                                {
                                    var files = Directory.GetFiles( _folderBrowserDialog.SelectedPath, "*.*", SearchOption.AllDirectories );
                                    _lastTimeItemInserted = DateTime.Now;
                                    foreach (var fileName in files)
                                    {
                                        if (fileName.EndsWith( ".mkv" ) || fileName.EndsWith( ".avi" ))
                                        {
                                            InitManagerIfNeeded();
                                            _subsDownloaderManager.DownloadSubtitles( fileName );
                                        }
                                    }
                                } );
            }
        }

        private void ToolStripButtonStopClick ( object sender, EventArgs e )
        {
            if (_subsDownloaderManager != null)
            {
                _subsDownloaderManager.Stop();
            }
        }

        private void ToolStripButtonStartClick ( object sender, EventArgs e )
        {
            InitManagerIfNeeded();

            _subsDownloaderManager.StartAsync();
            _toolStripButtonStart.Enabled = false;
            _toolStripButtonStop.Enabled = true;
        }

        private void InitManagerIfNeeded ()
        {
            if (_subsDownloaderManager == null)
            {
                _subsDownloaderManager = new DownloaderManager();
                _subsDownloaderManager.FileRecived += SubsDownloaderManagerFileRecived;
                _subsDownloaderManager.NoTitleMatchFound += SubsDownloaderManagerNoTitleMatchFound;
                _subsDownloaderManager.NoSubtitleMatchFound += SubsDownloaderManagerNoSubtitleMatchFound;
            }
        }

        private void AboutToolStripMenuItemClick ( object sender, EventArgs e )
        {
            _aboutBox.ShowDialog();
        }

        #endregion

        private void RenameTitlesToolStripMenuItemClick ( object sender, EventArgs e )
        {
            TextForm textForm = new TextForm();
            var titleFileInfos = (List<TitleFileInfo>)_treeViewTitlesView.SelectedNode.Tag;
            textForm.UserText = titleFileInfos[0].TitleName;
            textForm.Text = "Set New Name";
            if (textForm.ShowDialog( this ) == DialogResult.OK)
            {
                foreach (var titleFileInfo in titleFileInfos)
                {
                    titleFileInfo.TitleName = textForm.UserText;
                }
                _treeViewTitlesView.SelectedNode.Text = textForm.UserText;
                _treeViewTitlesView.SelectedNode.Name = textForm.UserText;
            }
        }

        private void ContextMenuStripTreeOpening ( object sender, System.ComponentModel.CancelEventArgs e )
        {
            if (_treeViewTitlesView.SelectedNode == _allNode ||
                _treeViewTitlesView.SelectedNode == _seriesNode ||
                _treeViewTitlesView.SelectedNode == _moviesNode)
            {
                e.Cancel = true;
            }
        }

        private void TreeViewTitlesViewMouseUp ( object sender, MouseEventArgs e )
        {
            // Show menu only if the right mouse button is clicked.
            if (e.Button == MouseButtons.Right)
            {

                // Point where the mouse is clicked.
                Point p = new Point( e.X, e.Y );

                // Get the node that the user has clicked.
                TreeNode node = _treeViewTitlesView.GetNodeAt( p );
                if (node != null)
                {

                    // Select the node the user has clicked.
                    // The node appears selected until the menu is displayed on the screen.
                    _treeViewTitlesView.SelectedNode = node;
                }
            }
        }

        private void ReSearchToolStripMenuItem1Click ( object sender, EventArgs e )
        {
            foreach (var titleInfo in _fastObjectListView.Objects.Cast<TitleFileInfo>())
            {
                _subsDownloaderManager.DownloadSubtitles( titleInfo, true );
            }
        }
    }
}
